module VersionControl;
import tango.io.Stdout;
import tango.io.FileScan;
import tango.io.FileConduit;
import tango.io.Print;
import tango.io.protocol.Reader;
import tango.text.convert.Layout;
import tango.text.stream.LineIterator;
import tango.io.Console;
import tango.text.convert.Integer;
import Text = tango.text.Util;
import FileInfo;
import Version;


final class VersionControl{
	
	this(char[] ndirectory,char[] hashalg){
		directory=ndirectory.dup;
		files = new FileMgr(directory, hashalg);
		loadVersionHistory;
		Stdout.format ("{} versions loaded\n", versions.length);
		checkForNewVersion;
	}
	
	void checkForNewVersion(){
		auto v=files.checkRepository();
		if (v is null) return;
		versions~=*v;
		saveVersionHistory;
	}
	
	bool getChangeset(int from,inout char[][] tosend,inout char[][] todelete){
		if((from+1)==versions.length) return false;
		for(int i=from+1; i<versions.length; ++i){
			//Stdout(i);
			Version* v=&versions[i];
			foreach(added; v.added){
				addifnotin(tosend, added);
				delifin(todelete,added);
			}
			
			foreach(mod; v.modyfied){
				addifnotin(tosend, mod);
				delifin(todelete,mod);
			}
			
			foreach(del; v.delated){
				addifnotin(todelete, del);
				delifin(tosend,del);
			}
		}
		
		//Stdout(tosend.length);
		//Stdout(todelete.length);
		
		if((tosend.length==0)&&(todelete.length==0)) return false;
		return true;
	}
		
	private:
	
	void addifnotin(inout char[][] a, char[] b){
		foreach(inout i; a){
			if (i==b) return;
		}
		a~=b.dup;
	}
	
	void delifin(inout char[][] a, char[] b){
		for(int i=0; i<a.length; ++i){
			if(a[i]==b){
				a[i]=a[$-1];
				a.length=a.length-1;
			}
		}
	}
	
	void loadVersionHistory(){
		auto fc = new FileConduit (directory~"\\info\\versions.cfg", FileConduit.ReadExisting);
		Version* v=null;
		foreach (line; new LineIterator!(char) (fc)){
			if(line.length==0) break;
			if( Text.containsPattern!(char)(line,"Version")){
				if(v !is null) versions~=*v;
				v= new Version;
			}else{
				switch(line[0]){
					case 'A': v.added~=line[2..$].dup; break;
					case 'M': v.modyfied~=line[2..$].dup; break;
					case 'D': v.delated~=line[2..$].dup; break;
					default: assert(false); break;
				}
			}
		}
		if(v !is null) versions~=*v;
		fc.close;
	}
	
	void saveVersionHistory(){
		auto fc = new FileConduit (directory~"\\info\\versions.cfg", FileConduit.WriteCreate);
		auto writeshit = new Print!(char) (new Layout!(char),fc, null);
		
		foreach(i, ver; versions){
			writeshit("Version ")(i)("\n")();
			foreach(file;ver.added){
				writeshit("A ")(file)("\n")();
			}
			foreach(file;ver.modyfied){
				writeshit("M ")(file)("\n")();
			}
			foreach(file;ver.delated){
				writeshit("D ")(file)("\n")();
			}
		}
		fc.close();
	}
	
	Version[] versions;
	int current;
	FileMgr files;
	char[] directory;
}